#ifndef     _CSVPARSER_HPP_
# define    _CSVPARSER_HPP_

# include <stdexcept>
# include <string>
# include <vector>
# include <list>
# include <sstream>
#include <unordered_map>

namespace csv
{
    class Error : public std::runtime_error
    {

      public:
        Error(const std::string &msg):
          std::runtime_error(std::string("CSVparser : ").append(msg))
        {
        }
    };

    class Parser;

    class Row
    {
    	public:
    	    Row(Parser *);
    	    ~Row(void);

    	public:
            unsigned int size(void) const;
            void push(unsigned int pos, unsigned int index);
            // bool set(const std::string &, const std::string &);
            void clear();
    	private:
            Parser* _parser;
            std::vector<unsigned int> _values;
        public:

//            template<typename T>
//            const T getValue(unsigned int pos) const
//            {
//                if (pos < _values.size())
//                {
//                    T res;
//                    std::stringstream ss;
//                    ss << _values[pos];
//                    ss >> res;
//                    return res;
//                }
//                T ret;
//                return ret;
//            }

            const std::vector<std::string>& getHeader() const;
            void dump(const char* info) const;

            unsigned int getValueByIndex(unsigned int pos) const
            {
                return _values[pos];
            }

            const std::string& operator[](unsigned int) const;
            const std::string& operator[](const std::string &valueName) const;
            // friend std::ostream& operator<<(std::ostream& os, const Row &row);
            // friend std::ofstream& operator<<(std::ofstream& os, const Row &row);
    };

    typedef std::unordered_map<std::string, Row*> RowDict;

    enum DataType {
        eFILE = 0,
        ePURE = 1
    };

    class Parser
    {

    public:
        Parser(const std::string &, const DataType &type = eFILE, char sep = ',');
        ~Parser(void);

    public:
        const RowDict& getRows() const;
        Row* getRow(const std::string &key) const;
        unsigned int rowCount(void) const;
        unsigned int columnCount(void) const;
        const std::vector<std::string>& getHeader(void) const;
        const std::string& getHeaderElement(unsigned int pos) const;
        const std::string& getColumnElement(unsigned int column, unsigned int pos) const;
        int getHeaderPos(const std::string &key) const;
        const std::string &getFileName(void) const;

    public:
        // bool deleteRow(const std::string &key);
        // bool addRow(const std::string &key, const std::vector<std::string> &);
        // void sync(void) const;

    protected:
    	void parseHeader(std::string line);
        void parseColumn(unsigned int pos, std::string line);
        void parseContent(std::string line);

    private:
        std::string _file;
        const DataType _type;
        const char _sep;
        std::vector<std::string> _header;
        std::vector<std::vector<std::string>> _columnValues;
        RowDict _content;

    public:
        Row* operator[](const std::string &key) const;
    };
}

#endif /*!_CSVPARSER_HPP_*/
